{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 功能梳理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 线程列表：使用`std::vector<std::unique_ptr<Thread>> threads_`存储线程对象，每个线程对象代表一个可独立执行的线程\n",
    "- 任务队列：通过`std::queue<std::shared_ptr<Task>> taskQue_`管理待处理任务，配合`std::mutex taskQueMtx_`保证线程安全\n",
    "- 同步机制：采用两个条件变量`notFull_`和`notEmpty_`分别表示任务队列未满和未空的状态\n",
    "- 线程函数：所有线程启动后执行`threadFunc`函数，该函数负责从任务队列消费任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 线程池使用方式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池构造与析构\n",
    "\n",
    "- 构造禁用：通过`ThreadPool(const ThreadPool&) = delete`禁止拷贝构造，确保线程池实例唯一性\n",
    "- 默认构造：提供无参构造函数初始化成员变量，如设置默认线程数 $initThreadSize_=4$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "设置线程池工作模式 \n",
    "\n",
    "- 模式选择：通过`setMode(PoolMode mode)`设置工作模式，支持fixed（固定线程数）和cached（动态增长）两种模式\n",
    "- 队列阈值：`setTaskQueMaxThreshHold方`法可调整任务队列最大容量，默认值为1024"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "启动线程池\n",
    "\n",
    "初始化过程：\n",
    "- 创建线程对象并绑定线程函数：`std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this))`\n",
    "- 将线程对象移入容器：`threads_.emplace_back(std::move(ptr))`\n",
    "- 逐个启动线程：`threads_[i]->start()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "提交任务\n",
    "\n",
    "- 任务封装：要求用户继承抽象基类`Task`并重写`run()`方法实现具体任务逻辑\n",
    "- 智能指针传递：提交接口`submitTask`接收`std::shared_ptr<Task>`参数，推荐使用`std::make_shared`创建任务对象\n",
    "- 队列满处理：当队列满时等待1秒，超时则返回提交失败提示\"task queue is full\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "示例：线程池使用\n",
    "\n",
    "- 标准流程：\n",
    "  - 创建线程池实例：`ThreadPool pool`\n",
    "  - 设置工作模式（可选）：`pool.setMode(PoolMode::fixed)`\n",
    "  - 启动线程池：`pool.start(4)`\n",
    "  - 创建任务类：继承`Task`实现`run()`方法\n",
    "  - 提交任务：`pool.submitTask(std::make_shared<MyTask>())`\n",
    "- 最佳实践：在公共库开发时应提供完整的使用示例（example），包含常用接口说明和使用流程演示"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 测试代码"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目测试代码介绍 \n",
    "\n",
    "- 测试代码结构：测试代码包含`main`函数，程序执行从此处开始\n",
    "- 线程休眠测试：使用`std::this_thread::sleep_for(std::chrono::seconds(2))`让线程休眠2秒进行基础测试\n",
    "- 调试打印：在代码中添加打印语句用于观察线程执行情况"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目中的线程函数\n",
    "\n",
    "- 线程创建：使用`std::make_unique`创建线程，绑定`ThreadPool::threadFunc`函数\n",
    "- 线程启动：通过`threads_.emplace_back`将线程加入容器，调用`start()`方法启动\n",
    "- 线程函数流程：\n",
    "  - 打印线程ID：输出`begin/end threadFunc`及线程ID\n",
    "  - 任务获取循环：使用无限循环持续从任务队列获取任务\n",
    "  - 锁机制：使用`unique_lock`保护任务队列访问"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目中的任务执行\n",
    "\n",
    "- 任务基类：定义`Task`基类，包含虚函数`run()`\n",
    "- 自定义任务：`MyTask`继承`Task`，重写`run()`方法\n",
    "  - 执行逻辑：打印线程ID，休眠2秒模拟任务执行\n",
    "  - 多态调用：线程池通过基类指针调用派生类的run方法\n",
    "- 任务提交：使用`pool.submitTask(std::make_shared<MyTask>())`提交任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目中的任务提交与获取\n",
    "\n",
    "- 任务获取步骤：\n",
    "  - 获取互斥锁保护任务队列\n",
    "  - 等待`notEmpty`条件变量，直到队列不为空\n",
    "  - 从队列头部取出任务\n",
    "  - 减少任务计数\n",
    "- 状态打印：添加\"尝试获取任务...\"和\"获取任务成功...\"打印信息\n",
    "- 通知机制：\n",
    "  - 任务剩余通知：队列仍有任务时`notify_all`唤醒其他线程\n",
    "  - 队列空间通知：取出任务后`notify_all`通知可继续提交任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目中的任务队列满的情况\n",
    "\n",
    "- 队列容量：将`TASK_MAX_THRESHHOLD`修改为4，限制队列最多容纳4个任务\n",
    "- 测试场景：\n",
    "  - 设置4个线程\n",
    "  - 提交7个耗时5秒的任务\n",
    "  - 预期：4个任务被立即执行，2个因队列满提交失败\n",
    "- 失败处理：当队列满时输出\"task queue is full, submit task fail.\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目中的任务执行与提交结果\n",
    "\n",
    "- 执行流程观察：\n",
    "  - 4个线程同时获取并执行前4个任务\n",
    "  - 每个任务执行耗时5秒\n",
    "  - 执行完成后线程再次尝试获取新任务\n",
    "- 队列状态：\n",
    "  - 任务被取出后队列空间释放\n",
    "  - 后续任务可以继续提交\n",
    "  - 当队列再次满时新任务提交失败"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池项目中的多任务提交与执行情况\n",
    "\n",
    "- 测试结果分析：\n",
    "  - 共提交10个任务\n",
    "  - 8个任务成功执行（4个初始+4个后续）\n",
    "  - 2个任务因队列满提交失败\n",
    "- 线程状态：\n",
    "  - 执行完任务的线程会继续等待新任务\n",
    "  - 当队列为空时线程阻塞在条件变量上\n",
    "- 预期验证：测试结果完全符合线程池设计的预期行为"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务返回值问题思考"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池应用场景 \n",
    "\n",
    "- 广泛应用性：线程池在很多场景下都会被使用，特别是在需要高效处理多任务的系统中\n",
    "- 典型示例：如网络程序中处理用户连接和读写事件"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "网络程序中的线程池使用\n",
    "\n",
    "- 主线程分工：主线程负责接收新用户连接，生成套接字`fd`\n",
    "- 工作线程职责：将连接分配给线程池中的线程处理已连接用户的读写事件\n",
    "- 事件驱动模型：每个线程都可以是一个`epoll`实例，专注于处理分配的事件"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "不需要返回值的场景\n",
    "\n",
    "- 独立处理特性：在网络编程场景中，各线程独立处理自己的任务即可\n",
    "- 无返回值需求：线程只需完成读写操作，不需要向主线程返回处理结果\n",
    "- 效率优先：这种设计避免了线程间通信开销，提高了整体处理效率"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多线程计算任务举例\n",
    "\n",
    "- 计算密集型案例：计算1到30000的和\n",
    "- 任务划分方法：\n",
    "  - 线程1：计算1到10000的和\n",
    "  - 线程2：计算10001到20000的和\n",
    "  - 线程3：计算20001到30000的和\n",
    "- 硬件优势利用：在多核CPU上并行计算可显著提高计算速度"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "主线程合并结果的需求\n",
    "\n",
    "- 主线程职责：\n",
    "  - 分配计算区间给各工作线程\n",
    "  - 等待所有线程完成计算\n",
    "  - 合并各线程返回的部分和\n",
    "- 同步机制需求：需要设计机制让主线程能获取工作线程的计算结果\n",
    "- 阻塞等待特性：当任务未完成时，获取结果的调用应该阻塞等待"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MyTask类设计\n",
    "\n",
    "- 构造函数设计：通过构造函数接收计算区间的起止值(begin和end)\n",
    "- `run`方法实现：在`run`方法中完成指定区间的累加计算\n",
    "- 变量命名规范：使用有意义的变量名如`begin_`和`end_`提高代码可读性\n",
    "- 计算逻辑：使用`for`循环累加指定范围内的整数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务执行与返回值问题\n",
    "\n",
    "- 返回值多样性：不同任务可能返回不同类型(`int`, `string`, `json`等)\n",
    "- 设计挑战：\n",
    "  - 如何设计`run`方法的返回值表示任意类型\n",
    "  - 如何实现任务与返回值的关联机制\n",
    "- 模板限制：虚函数不能与模板函数共存，因为虚函数表需要在编译时确定"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "返回值获取机制设计\n",
    "\n",
    "- `Result`对象需求：需要设计一个与任务关联的`Result`对象\n",
    "- 阻塞获取特性：当任务未完成时，`get()`方法应该阻塞调用者\n",
    "- 类型通用性：机制需要支持各种可能的返回值类型\n",
    "- 关联设计：`Result`需要与提交的任务紧密关联"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "课程目标与思考\n",
    "\n",
    "- 教学目的：通过自己实现这些机制加深对C++原理的理解\n",
    "- 拒绝直接使用：虽然C++17/20已提供相关功能，但选择从底层实现\n",
    "- 思考重点：如何设计通用的返回值机制和任务关联机制\n",
    "- 实践价值：这些设计模式在实际C++开发工作中经常使用"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
